package org.paboo.util;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import org.apache.batik.anim.dom.SVGDOMImplementation;

import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class ZxingImage {

    private static LoggerFactoryUtils log = LoggerFactoryUtils.getInstance().load(ZxingImage.class);
    
    public static final int BLACK = 0x000000;
    public static final int WHITE = 0xFFFFFF;

    /*
     * Note that the input matrix uses 0 == white, 1 == black, while the output
     * matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
     */

    /**
     *
     * @param input Byte Matrix
     * @param width Image Width
     * @param height Image Height
     * @param margin QR Code Margin
     * @return Bit Matrix
     */
    public static BitMatrix resultDecodec(ByteMatrix input, int width, int height, int margin) {
        if (input == null) {
            throw new IllegalStateException();
        }
        int inputWidth = input.getWidth();
        int inputHeight = input.getHeight();
        log.debug("Matrix Size:" + inputWidth + "*" + inputHeight);
        int qrWidth = inputWidth + (margin * 2);
        int qrHeight = inputHeight + (margin * 2);
        int outputWidth = Math.max(width, qrWidth);
        int outputHeight = Math.max(height, qrHeight);
        log.debug("Output Size:" + outputWidth + "*" + outputHeight);
        int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
        log.debug("Multiple:" + multiple);
        int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
        int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
        log.debug("Top Padding:" + topPadding);
        log.debug("Left Padding:" + leftPadding);
        BitMatrix output = new BitMatrix(outputWidth, outputHeight);

        for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
            for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
                if (input.get(inputX, inputY) == 1) {
                    output.setRegion(outputX, outputY, multiple, multiple);
                }
            }
        }

        return output;
    }

    /**
     *
     * @param matrix Bit Matrix
     * @param bgColor Background Color
     * @param fgColor Code Color
     * @return Image Object
     */
    public static BufferedImage toBufferedImage(BitMatrix matrix, int bgColor, int fgColor) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height,
                (fgColor == BLACK && bgColor == WHITE) ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? fgColor : bgColor);
            }
        }
        return image;
    }

    public static void toSVGImage(BitMatrix matrix, OutputStream os, int bgColor, int fgColor) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        Color bg = new Color(bgColor);
        Color fg = new Color(fgColor);

        DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
        String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
        Document document = impl.createDocument(svgNS, "svg", null);

        // Get a DOMImplementation.
        //DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();

        // Create an instance of org.w3c.dom.Document.
        // svgNS = "http://www.w3.org/2000/svg";
        // document = domImpl.createDocument(svgNS, "svg", null);

        // Get the root element (the 'svg' element).
        //Element svgRoot = document.getDocumentElement();

        // Create an instance of the SVG Generator.
        SVGGraphics2D g2d = new SVGGraphics2D(document);
        g2d.setSVGCanvasSize(new Dimension(width, height));

        //Graphics2D g2d = new EpsGraphics2D("QRCode");
        g2d.setStroke(new BasicStroke(1.0f));
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (matrix.get(x, y)){
                    if (g2d.getColor() != fg){
                        g2d.setColor(fg);
                    }
                    g2d.drawRect(x, y, 1, 1);
                    Color c = fg;
                    //System.out.println(c.getRed() + " " + c.getGreen() + " " + c.getBlue());
                }
                else {
                    if (g2d.getColor() != bg){
                        g2d.setColor(bg);
                    }
                    g2d.drawRect(x, y, 1, 1);
                }
            }
        }

        try {
            g2d.stream(new OutputStreamWriter(new BufferedOutputStream(os)));
        } catch (SVGGraphics2DIOException e) {
            e.printStackTrace();
        }

    }
}
